#!/usr/bin/env python

import wx
import app
import time
import model
import thread
import logging
import datetime
import component
import threading
import messaging.sms

class Progress(object):
    '''Progress class
    
    @author Julot <andy.julot@gmail.com>
    @since Thursday, March 01, 2012. 10:35 AM'''
    
    busy = False
    stopped = False
    _read = False
    _port = 'COM1'
    _baudrate = 115200
    
    def __init__(self, view, interactor):
        self.view = view
        self.interactor = interactor
        self.readConfig()
        self.populate()
        
        thread.start_new_thread(self.startModemDaemon, ())
    
    def __del__(self):
        self.writeConfig()
    
    def readConfig(self):
        config = app.Config()
        
        self._port = config.Read('Modem/Port', 'COM1')
        self._baudrate = config.ReadInt('Modem/Baudrate', 115200)
        self._checkInterval = config.ReadInt('Modem/CheckInterval', 0)
        
        key = '%s/ProgressOutboxNumber' % self.view.Name
        pos = config.ReadInt(key, 150)
        self.view.progress.outbox.SetColumnWidth(0, pos)
    
    def writeConfig(self):
        config = app.Config()
        key = '%s/ProgressOutboxNumber' % self.view.Name
        config.WriteInt(key, self.view.progress.outbox.GetColumnWidth(0))
    
    _shouldCheckOutbox = True
    
    def checkOutbox(self):
        self.populate()
        self._shouldCheckOutbox = True
    
    def populate(self):
        with threading.RLock():
            outboxes = model.Outbox.objects.query().order_by('id')
            self.view.progress.outbox.models = outboxes
    
    def loadFirstOutbox(self):
        with threading.RLock():
            outbox = model.Outbox.objects.query().order_by('id')[0]
            return outbox.attributes if outbox else None
    
    def deleteOutbox(self, id):
        with threading.RLock():
            message = model.Outbox.objects.get(id)
            if message: message.delete()
    
    def appendOutbox(self, outboxAttributes):
        with threading.RLock():
            outbox = model.Outbox()
            outbox.number = outboxAttributes.number
            outbox.message = outboxAttributes.message
        
    def loadModem(self):
        try:
            modem = component.Modem(self._port, self._baudrate)
            modem.echoOff()
            modem.changeMode()
            modem.changeMessageStorage()
            return modem
        except:
            s = 'Error connecting to modem.'
            wx.CallAfter(self.view.StatusBar.SetStatusText, (s))
            return None
    
    def saveInboxes(self, messages):
        # Because we are in GMT+7 and didn't want to bother with UTC
        timeDelta = datetime.timedelta(hours=7)
        
        with threading.RLock():
            for message in messages:
                sms = model.Message()
                sms.pdu = message.pdu
                sms.labels = [sms.LABEL_INBOX]
                sms.dateTime = message.date + timeDelta
                sms.numbers = [message.number]
                sms.reference = 0
                sms.total = 1
                sms.sequence = 0
                if message.udh:
                    sms.reference = message.udh.concat.ref
                    sms.total = message.udh.concat.cnt
                    sms.sequence = message.udh.concat.seq
                sms.message = message.text
                sms.save()
    
    def read(self):
        self.view.messages.toolBar.read.disable()
        self.view.MenuBar.message.read.Enable(False)
        self._read = True
    
    def startModemDaemon(self):
        time.sleep(1)
        startTime = datetime.datetime(2012, 02, 15)
        timeDelta = datetime.timedelta(seconds=self._checkInterval)
        
        while not self.stopped:
            if self._shouldCheckOutbox:
                modem = self.loadModem()
                if modem:
                    message = self.loadFirstOutbox()
                    if message:
                        self.busy = True
                        sent = modem.sms.send(message.number, message.message)
                        self.deleteOutbox(message.id)
                        wx.CallAfter(self.view.progress.outbox.DeleteItem, (0))
                        if not sent:
                            self.appendOutbox(message)
                            wx.CallAfter(self.view.progress.outbox.append,
                                         (message))
                        self.busy = False
                        if not sent: time.sleep(60)
                    else:
                        self._shouldCheckOutbox = False
                    modem.close()
                else:
                    wx.CallAfter(self.view.setStatus, ('Modem error.'))
                    self._shouldCheckOutbox = False
                    time.sleep(60)
                del modem
            
            if self.stopped: break
            
            if (not self._read) and (not self._checkInterval):
                if not self._shouldCheckOutbox: time.sleep(1)
                continue
            
            if self.stopped: break
            
            if (not self._read) and \
               datetime.datetime.now() < startTime + timeDelta:
                if not self._shouldCheckOutbox: time.sleep(1)
                continue
            
            if self.stopped: break
            
            wx.CallAfter(self.view.setStatus, ('Reading SMS...'))
            modem = self.loadModem()
            if modem:
                self.busy = True
                messages = modem.sms.list()
                self.saveInboxes(messages)
                for message in messages:
                    modem.sms.delete(message.index)
                modem.close()
                del modem
                self.busy = False
                wx.CallAfter(self.view.setStatus, ('Reading SMS completed.'))
            else:
                s = 'Modem error. Will sleep for 60 seconds.'
                wx.CallAfter(self.view.setStatus, (s))
                del modem
                time.sleep(60)
            wx.CallAfter(self.view.messages.toolBar.read.enable, (True))
            wx.CallAfter(self.view.MenuBar.message.read.Enable, (True))
            startTime = datetime.datetime.now()
            self._read = False
